package com.lucifer.treasure.enchant.effect;

import com.lucifer.treasure.registry.EnchantRegistry;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents;
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
import net.minecraft.enchantment.EnchantmentEffectContext;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.EnchantmentLevelBasedValue;
import net.minecraft.enchantment.effect.EnchantmentEntityEffect;
import net.minecraft.entity.Entity;
import net.minecraft.entity.ExperienceOrbEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;

public record ExperienceBoostEnchantmentEffect(EnchantmentLevelBasedValue bonusExp) implements EnchantmentEntityEffect {
    public static final MapCodec<ExperienceBoostEnchantmentEffect> CODEC = RecordCodecBuilder.mapCodec(instance ->
            instance.group(
                    EnchantmentLevelBasedValue.CODEC.fieldOf("bonus_exp").forGetter(ExperienceBoostEnchantmentEffect::bonusExp)
            ).apply(instance, ExperienceBoostEnchantmentEffect::new)
    );

    public static void initialize() {
        // 监听方块破坏事件 - 增加挖掘经验
        PlayerBlockBreakEvents.AFTER.register((world, player, pos, state, blockEntity) -> {
            // 首先检查配置是否启用此附魔
            if (!EnchantRegistry.isEnchantEnabled("experience_boost")) {
                return;
            }

            if (world.isClient() || !(player instanceof PlayerEntity)) {
                return;
            }

            // 检查主手和副手工具的Experience Boost附魔等级
            int maxLevel = 0;
            maxLevel = Math.max(maxLevel, getExperienceBoostLevel(player.getMainHandStack()));
            maxLevel = Math.max(maxLevel, getExperienceBoostLevel(player.getOffHandStack()));

            if (maxLevel <= 0) {
                return;
            }

            // 计算额外经验 - 基于方块类型和附魔等级
            int bonusExp = calculateBonusExp(maxLevel, state, world, pos);
            if (bonusExp > 0) {
                spawnExperienceOrbs(world, pos, bonusExp);
            }
        });

        // 监听生物死亡事件 - 增加击杀经验
        ServerLivingEntityEvents.AFTER_DEATH.register((entity, damageSource) -> {
            if (!(damageSource.getAttacker() instanceof PlayerEntity attacker)) {
                return;
            }

            // 检查主手和副手武器的Experience Boost附魔等级
            int maxLevel = 0;
            maxLevel = Math.max(maxLevel, getExperienceBoostLevel(attacker.getMainHandStack()));
            maxLevel = Math.max(maxLevel, getExperienceBoostLevel(attacker.getOffHandStack()));

            if (maxLevel <= 0) {
                return;
            }

            // 计算额外经验 - 基于生物类型和附魔等级
            int bonusExp = calculateKillBonusExp(maxLevel, entity.getType().getSpawnGroup());
            if (bonusExp > 0) {
                spawnExperienceOrbs(attacker.getWorld(), entity.getBlockPos(), bonusExp);

                // 生成经验特效 - 使用经验相关的粒子
                if (attacker.getWorld() instanceof ServerWorld serverWorld) {
                    // 使用附魔光泽粒子，更符合经验提升的主题
                    serverWorld.spawnParticles(
                            net.minecraft.particle.ParticleTypes.ENCHANT,
                            entity.getX(), entity.getY() + entity.getHeight() * 0.5, entity.getZ(),
                            Math.min(bonusExp * 2, 15), 0.5, 0.3, 0.5, 0.8
                    );

                    // 添加金色闪亮粒子效果
                    serverWorld.spawnParticles(
                            net.minecraft.particle.ParticleTypes.GLOW,
                            entity.getX(), entity.getY() + entity.getHeight() * 0.5, entity.getZ(),
                            Math.min(bonusExp, 8), 0.3, 0.2, 0.3, 0.1
                    );
                }
            }
        });
    }

    /**
     * 计算挖掘方块的额外经验奖励
     * 修改：大幅提升经验倍数，更明显的效果
     * 新公式：基础经验 = (等级 * 2) + sqrt(等级 * 3)，更强的递增效果
     *
     * @param level 附魔等级 (无上限)
     * @param state 方块状态
     * @param world 世界
     * @param pos   方块位置
     * @return 额外经验值
     */
    private static int calculateBonusExp(int level, net.minecraft.block.BlockState state, net.minecraft.world.World world, net.minecraft.util.math.BlockPos pos) {
        // 检查方块是否会掉落经验
        int originalExp = getBlockExperience(state, world, pos);
        if (originalExp <= 0) {
            return 0; // 只对有经验的方块增加经验
        }

        // 增强基础经验：(等级 * 2) + sqrt(等级 * 3)，提供更强的递增收益
        double baseExpMultiplier = (level * 2.0) + Math.sqrt(level * 3.0);

        // 大幅提升基于原始经验的倍数计算
        // 使用2.0-6.0倍的范围，基于附魔等级调整
        double multiplier = 2.0 + (Math.min(level, 20) * 0.2); // 最高6.0倍（等级20+）

        int bonusExp = (int) Math.round(originalExp * multiplier * (baseExpMultiplier / 8.0));
        return Math.max(2, bonusExp); // 最少给2经验
    }

    /**
     * 获取方块破坏时掉落的经验值
     * 兼容原版和模组添加的所有掉经验的方块
     */
    private static int getBlockExperience(net.minecraft.block.BlockState state, net.minecraft.world.World world, net.minecraft.util.math.BlockPos pos) {
        // 使用方块的getExperienceDropped方法获取经验
        // 这是Fabric版本的正确方法
        net.minecraft.block.Block block = state.getBlock();

        // 尝试获取方块的经验掉落
        if (block instanceof net.minecraft.block.ExperienceDroppingBlock) {
            // 使用反射或直接调用来获取经验
            // 由于ExperienceDroppingBlock可能没有公共方法，我们使用另一种方式
        }

        // 直接使用方块ID来判断是否为掉经验的方块
        String blockId = net.minecraft.registry.Registries.BLOCK.getId(block).toString();

        // 检查已知的掉经验方块
        if (blockId.equals("minecraft:coal_ore") || blockId.equals("minecraft:deepslate_coal_ore")) {
            return 1 + world.getRandom().nextInt(3); // 0-2经验，平均1.5
        }
        if (blockId.equals("minecraft:diamond_ore") || blockId.equals("minecraft:deepslate_diamond_ore")) {
            return 3 + world.getRandom().nextInt(5); // 3-7经验，平均5
        }
        if (blockId.equals("minecraft:emerald_ore") || blockId.equals("minecraft:deepslate_emerald_ore")) {
            return 3 + world.getRandom().nextInt(5); // 3-7经验，平均5
        }
        if (blockId.equals("minecraft:lapis_ore") || blockId.equals("minecraft:deepslate_lapis_ore")) {
            return 2 + world.getRandom().nextInt(4); // 2-5经验，平均3.5
        }
        if (blockId.equals("minecraft:nether_quartz_ore")) {
            return 2 + world.getRandom().nextInt(4); // 2-5经验，平均3.5
        }
        if (blockId.equals("minecraft:redstone_ore") || blockId.equals("minecraft:deepslate_redstone_ore")) {
            return 1 + world.getRandom().nextInt(4); // 1-5经验，平均3
        }
        if (blockId.equals("minecraft:nether_gold_ore")) {
            return world.getRandom().nextInt(2); // 0-1经验，平均0.5
        }

        // Sculk系列方块
        if (blockId.equals("minecraft:sculk") || blockId.equals("minecraft:sculk_vein") ||
                blockId.equals("minecraft:sculk_catalyst") || blockId.equals("minecraft:sculk_shrieker") ||
                blockId.equals("minecraft:sculk_sensor")) {
            return 1; // 1经验
        }

        // 生物生成笼
        if (blockId.equals("minecraft:spawner")) {
            return 15 + world.getRandom().nextInt(29); // 15-43经验，平均29
        }

        // 检查是否为模组矿物（通过检查方块ID是否含有"ore"）
        if (blockId.contains("ore") && !blockId.contains("storage") && !blockId.contains("block")) {
            // 对于模组矿物，给予基础经验
            return 1 + world.getRandom().nextInt(3); // 1-3经验，平均2
        }

        return 0; // 不掉经验的方块
    }

    /**
     * 计算击杀生物的额外经验奖励
     * 新公式：基础经验 = (等级 * 2.5) + sqrt(等级 * 4) + 生物类型奖励
     *
     * @param level      附魔等级 (无上限)
     * @param spawnGroup 生物群组
     * @return 额外经验值
     */
    private static int calculateKillBonusExp(int level, net.minecraft.entity.SpawnGroup spawnGroup) {
        // 增强基础经验：(等级 * 2.5) + sqrt(等级 * 4)，提供更强的高等级收益
        double baseExp = (level * 2.5) + Math.sqrt(level * 4.0);

        // 根据生物类型调整
        double typeMultiplier = 1.0;
        switch (spawnGroup) {
            case MONSTER:
                typeMultiplier = 1.8; // 怪物给80%额外经验
                break;
            case CREATURE:
                typeMultiplier = 1.0; // 动物给100%经验
                break;
            case WATER_CREATURE:
            case WATER_AMBIENT:
                typeMultiplier = 1.1; // 水生生物给110%经验
                break;
            case AMBIENT:
                typeMultiplier = 0.8; // 环境生物（蝙蝠等）给80%经验
                break;
            default:
                typeMultiplier = 1.2;
                break;
        }

        return Math.max(1, (int) Math.round(baseExp * typeMultiplier));
    }

    /**
     * 在指定位置生成经验球
     *
     * @param world    世界
     * @param pos      位置
     * @param totalExp 总经验值
     */
    private static void spawnExperienceOrbs(World world, BlockPos pos, int totalExp) {
        if (!(world instanceof ServerWorld serverWorld)) {
            return;
        }

        // 将经验分散成多个经验球
        while (totalExp > 0) {
            int orbValue = ExperienceOrbEntity.roundToOrbSize(totalExp);
            totalExp -= orbValue;

            ExperienceOrbEntity expOrb = new ExperienceOrbEntity(
                    serverWorld,
                    pos.getX() + 0.5,
                    pos.getY() + 0.5,
                    pos.getZ() + 0.5,
                    orbValue
            );

            // 设置随机速度，让经验球散开
            expOrb.setVelocity(
                    (world.getRandom().nextDouble() - 0.5) * 0.3,
                    world.getRandom().nextDouble() * 0.3,
                    (world.getRandom().nextDouble() - 0.5) * 0.3
            );

            serverWorld.spawnEntity(expOrb);
        }
    }

    /**
     * 从物品栈获取Experience Boost附魔等级
     */
    private static int getExperienceBoostLevel(ItemStack stack) {
        if (stack.isEmpty()) {
            return 0;
        }

        var enchantments = EnchantmentHelper.getEnchantments(stack);
        int maxLevel = 0;

        for (var entry : enchantments.getEnchantments()) {
            if (entry.getKey().isPresent()) {
                String enchantmentId = entry.getKey().get().getValue().toString();
                if (enchantmentId.equals("lucifer_treasure:experience_boost")) {
                    maxLevel = Math.max(maxLevel, enchantments.getLevel(entry));
                }
            }
        }

        return maxLevel;
    }

    @Override
    public void apply(ServerWorld world, int level, EnchantmentEffectContext context, Entity target, Vec3d pos) {
        // 主要逻辑在事件监听器中处理
        if (context.owner() instanceof PlayerEntity player) {
            int bonusExp = level * 2; // 简单的等级倍数
            if (bonusExp > 0) {
                spawnExperienceOrbs(world, BlockPos.ofFloored(pos), bonusExp);
            }
        }
    }

    @Override
    public MapCodec<? extends EnchantmentEntityEffect> getCodec() {
        return CODEC;
    }
} 